Micron Document
NexusPi Git Node

Node / mirrors / MeshChatX / files / tests / backend / test_map_data_live_link.py

Displaying Raw • Download

tests/backend/test_map_data_live_link.py 443700a629eee5c0fcbbdf9908a62a3dec6218e8 (443700a6) Text, 10.97 KB

T8b949e# SPDX-License-Identifier: 0BSD

T8b949e"""Live map-data-v1 catalog fetch over an RNS Link on loopback TCP."""

Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations

Tff7b72import T7ee787json
Tff7b72import T7ee787socket
Tff7b72import T7ee787subprocess
Tff7b72import T7ee787sys
Tff7b72import T7ee787textwrap
Tff7b72import T7ee787time
Tff7b72from T7ee787pathlib Tff7b72import Te6edf3Path

Tff7b72from T7ee787testsT7ee787.T7ee787backendT7ee787.T7ee787eectT7ee787.T7ee787harness Tff7b72import Te6edf3eect_scenario
Tff7b72from T7ee787testsT7ee787.T7ee787backendT7ee787.T7ee787supportT7ee787.T7ee787test_temp_dir Tff7b72import Te6edf3subprocess_test_env

Te6edf3_PUB_SCRIPT Tff7b72= Te6edf3textwrapTff7b72.Td2a8ffdedentTb4b4b4(
Ta5d6ffrT8b949e"""
import json
import os
import sys
import time

import RNS

from meshchatx.src.backend.database import Database
from meshchatx.src.backend.map_data_manager import MapDataManager

GEOJSON = json.dumps(
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"name": "Camp"},
"geometry": {"type": "Point", "coordinates": [1.0, 2.0]},
},
],
},
).encode()


class FakeValue:
def __init__(self, value):
self._value = value

def get(self):
return self._value

def set(self, value):
self._value = value


class FakeConfig:
def __init__(self):
self.map_overlay_max_bytes = FakeValue(8 * 1024 * 1024)
self.map_overlay_max_features = FakeValue(50_000)
self.map_overlay_max_kmz_uncompressed_bytes = FakeValue(16 * 1024 * 1024)
self.map_overlay_path_timeout_seconds = FakeValue(8)
self.map_overlay_transfer_timeout_seconds = FakeValue(20)
self.map_overlay_job_timeout_seconds = FakeValue(25)
self.map_data_max_bytes = FakeValue(512 * 1024)
self.map_data_announce_enabled = FakeValue(False)
self.map_data_announce_interval = FakeValue(900)
self.map_data_display_name = FakeValue("Camp maps")

config_dir, share_dir = sys.argv[1], sys.argv[2]
stop_path = os.path.join(share_dir, "stop")
ready_path = os.path.join(share_dir, "ready.json")
RNS.Reticulum(configdir=config_dir, loglevel=RNS.LOG_ERROR)
identity = RNS.Identity()
db = Database(os.path.join(config_dir, "db.sqlite"))
db.initialize()
mgr = MapDataManager(
FakeConfig(),
db,
os.path.join(config_dir, "store"),
identity,
reticulum=RNS.Reticulum.get_instance(),
)
mgr.start()
if mgr._destination is not None:
raise SystemExit("destination created before publish")
published = mgr.publish_bytes(GEOJSON, name="Camp")
if mgr._destination is None:
raise SystemExit("destination missing after publish")
mgr.announce()
with open(ready_path, "w", encoding="utf-8") as handle:
json.dump(
{
"dest": mgr._destination.hash.hex(),
"pub": identity.get_public_key().hex(),
"map_id": published["map"]["map_id"],
},
handle,
)
deadline = time.time() + 45
while time.time() < deadline and not os.path.isfile(stop_path):
mgr.announce()
time.sleep(1.5)
RNS.exit(0)
"""
Tb4b4b4)

Te6edf3_CLI_SCRIPT Tff7b72= Te6edf3textwrapTff7b72.Td2a8ffdedentTb4b4b4(
Ta5d6ffrT8b949e"""
import asyncio
import json
import os
import sys
import time

import RNS

from meshchatx.src.backend.database import Database
from meshchatx.src.backend.map_data_manager import MapDataManager
from meshchatx.src.backend.rns_link_manager import RnsLinkManager


class FakeValue:
def __init__(self, value):
self._value = value

def get(self):
return self._value

def set(self, value):
self._value = value


class FakeConfig:
def __init__(self):
self.map_overlay_max_bytes = FakeValue(8 * 1024 * 1024)
self.map_overlay_max_features = FakeValue(50_000)
self.map_overlay_max_kmz_uncompressed_bytes = FakeValue(16 * 1024 * 1024)
self.map_overlay_path_timeout_seconds = FakeValue(12)
self.map_overlay_transfer_timeout_seconds = FakeValue(20)
self.map_overlay_job_timeout_seconds = FakeValue(25)
self.map_data_max_bytes = FakeValue(512 * 1024)
self.map_data_announce_enabled = FakeValue(False)
self.map_data_announce_interval = FakeValue(900)
self.map_data_display_name = FakeValue("Client")

config_dir, share_dir = sys.argv[1], sys.argv[2]
ready_path = os.path.join(share_dir, "ready.json")
result_path = os.path.join(share_dir, "result.json")
RNS.Reticulum(configdir=config_dir, loglevel=RNS.LOG_ERROR)
identity = RNS.Identity()
deadline = time.time() + 20
ready = None
while time.time() < deadline:
if os.path.isfile(ready_path):
with open(ready_path, encoding="utf-8") as handle:
ready = json.load(handle)
if ready.get("dest"):
break
time.sleep(0.2)
if not ready:
with open(result_path, "w", encoding="utf-8") as handle:
json.dump({"ok": False, "reason": "no_ready"}, handle)
RNS.exit(0)
raise SystemExit(0)
peer = bytes.fromhex(ready["dest"])
RNS.Identity.remember(
RNS.Identity.full_hash(peer),
peer,
bytes.fromhex(ready["pub"]),
)
path_deadline = time.time() + 20
while time.time() < path_deadline:
if RNS.Transport.has_path(peer) and RNS.Identity.recall(peer):
break
RNS.Transport.request_path(peer)
time.sleep(0.4)
db = Database(os.path.join(config_dir, "db.sqlite"))
db.initialize()
link_mgr = RnsLinkManager(
self_identity_getter=lambda: identity,
reticulum_getter=lambda: RNS.Reticulum.get_instance(),
broadcast_event=lambda _payload: None,
)
mgr = MapDataManager(
FakeConfig(),
db,
os.path.join(config_dir, "store"),
identity,
reticulum=RNS.Reticulum.get_instance(),
link_manager_getter=lambda: link_mgr,
)

async def run():
catalog = await mgr.fetch_catalog(peer.hex())
maps = catalog.get("maps") or []
if not maps:
return {"ok": False, "reason": "empty_catalog", "catalog": catalog}
body = await mgr.fetch_map_bytes(peer.hex(), maps[0]["id"])
return {
"ok": True,
"name": maps[0]["name"],
"map_id": maps[0]["id"],
"published_id": ready["map_id"],
"size": len(body),
"has_path": bool(RNS.Transport.has_path(peer)),
}

try:
payload = asyncio.run(run())
except Exception as exc:
payload = {"ok": False, "reason": str(exc)}
with open(result_path, "w", encoding="utf-8") as handle:
json.dump(payload, handle)
RNS.exit(0)
"""
Tb4b4b4)


Tff7b72def Td2a8ff_free_portTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657intTb4b4b4:
Te6edf3sock Tff7b72= Te6edf3socketTff7b72.Td2a8ffsocketTb4b4b4(Tb4b4b4)
Te6edf3sockTff7b72.Td2a8ffbindTb4b4b4(Tb4b4b4(Ta5d6ff"Ta5d6ff127.0.0.1Ta5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3port Tff7b72= Tffa657intTb4b4b4(Te6edf3sockTff7b72.Td2a8ffgetsocknameTb4b4b4(Tb4b4b4)Tb4b4b4[T79c0ff1Tb4b4b4]Tb4b4b4)
Te6edf3sockTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3port


Tff7b72def Td2a8ff_write_pairTb4b4b4(Te6edf3pub_dirTb4b4b4: Te6edf3PathTb4b4b4, Te6edf3cli_dirTb4b4b4: Te6edf3PathTb4b4b4, Te6edf3portTb4b4b4: Tffa657intTb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Te6edf3pub_dirTff7b72.Td2a8ffmkdirTb4b4b4(Te6edf3parentsTff7b72=Tff7b72TrueTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Te6edf3cli_dirTff7b72.Td2a8ffmkdirTb4b4b4(Te6edf3parentsTff7b72=Tff7b72TrueTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tb4b4b4(Te6edf3pub_dir Tff7b72/ Ta5d6ff"Ta5d6ffconfigTa5d6ff"Tb4b4b4)Tff7b72.Td2a8ffwrite_textTb4b4b4(
Ta5d6ff"Ta5d6ff[reticulum]Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ffenable_transport = YesTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ffshare_instance = NoTffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffshared_instance_port = Tffd700{T79c0ff37000 Tff7b72+ Tb4b4b4(Te6edf3port Tff7b72% T79c0ff1000Tb4b4b4)Tffd700}Tffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffinstance_name = map_data_pub_Tffd700{Te6edf3portTffd700}Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ffpanic_on_interface_error = NoTffea00\nTa5d6ff"
Ta5d6ff"Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff[logging]Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ffloglevel = 3Tffea00\nTa5d6ff"
Ta5d6ff"Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff[interfaces]Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff [[TCP Server]]Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff type = TCPServerInterfaceTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff enabled = YesTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff listen_ip = 127.0.0.1Tffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ff listen_port = Tffd700{Te6edf3portTffd700}Tffea00\nTa5d6ff"Tb4b4b4,
Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tb4b4b4(Te6edf3cli_dir Tff7b72/ Ta5d6ff"Ta5d6ffconfigTa5d6ff"Tb4b4b4)Tff7b72.Td2a8ffwrite_textTb4b4b4(
Ta5d6ff"Ta5d6ff[reticulum]Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ffenable_transport = YesTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ffshare_instance = NoTffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffshared_instance_port = Tffd700{T79c0ff38000 Tff7b72+ Tb4b4b4(Te6edf3port Tff7b72% T79c0ff1000Tb4b4b4)Tffd700}Tffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffinstance_name = map_data_cli_Tffd700{Te6edf3portTffd700}Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ffpanic_on_interface_error = NoTffea00\nTa5d6ff"
Ta5d6ff"Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff[logging]Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ffloglevel = 3Tffea00\nTa5d6ff"
Ta5d6ff"Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff[interfaces]Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff [[TCP Client]]Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff type = TCPClientInterfaceTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff enabled = YesTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff target_host = 127.0.0.1Tffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ff target_port = Tffd700{Te6edf3portTffd700}Tffea00\nTa5d6ff"Tb4b4b4,
Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4,
Tb4b4b4)


Tff7b72def Td2a8fftest_live_catalog_and_map_bytes_over_rns_linkTb4b4b4(Te6edf3tmp_pathTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3eect_scenarioTb4b4b4(Ta5d6ff"Ta5d6ffmap.data.live_catalog_linkTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3port Tff7b72= Te6edf3_free_portTb4b4b4(Tb4b4b4)
Te6edf3pub_dir Tff7b72= Te6edf3tmp_path Tff7b72/ Ta5d6ff"Ta5d6ffpubTa5d6ff"
Te6edf3cli_dir Tff7b72= Te6edf3tmp_path Tff7b72/ Ta5d6ff"Ta5d6ffcliTa5d6ff"
Te6edf3share_dir Tff7b72= Te6edf3tmp_path Tff7b72/ Ta5d6ff"Ta5d6ffshareTa5d6ff"
Te6edf3share_dirTff7b72.Td2a8ffmkdirTb4b4b4(Te6edf3parentsTff7b72=Tff7b72TrueTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Te6edf3_write_pairTb4b4b4(Te6edf3pub_dirTb4b4b4, Te6edf3cli_dirTb4b4b4, Te6edf3portTb4b4b4)
Te6edf3env Tff7b72= Te6edf3subprocess_test_envTb4b4b4(Tb4b4b4)
Te6edf3pub Tff7b72= Te6edf3subprocessTff7b72.Td2a8ffPopenTb4b4b4(
Tb4b4b4[Te6edf3sysTff7b72.Td2a8ffexecutableTb4b4b4, Ta5d6ff"Ta5d6ff-cTa5d6ff"Tb4b4b4, Te6edf3_PUB_SCRIPTTb4b4b4, Tffa657strTb4b4b4(Te6edf3pub_dirTb4b4b4)Tb4b4b4, Tffa657strTb4b4b4(Te6edf3share_dirTb4b4b4)Tb4b4b4]Tb4b4b4,
Te6edf3stdoutTff7b72=Te6edf3subprocessTff7b72.Td2a8ffPIPETb4b4b4,
Te6edf3stderrTff7b72=Te6edf3subprocessTff7b72.Td2a8ffPIPETb4b4b4,
Te6edf3textTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3envTff7b72=Te6edf3envTb4b4b4,
Tb4b4b4)
Te6edf3cli Tff7b72= Tff7b72None
Tff7b72tryTb4b4b4:
Te6edf3ready Tff7b72= Te6edf3share_dir Tff7b72/ Ta5d6ff"Ta5d6ffready.jsonTa5d6ff"
Te6edf3deadline Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72+ T79c0ff25
Tff7b72while Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3deadline Tff7b72and Tff7b72not Te6edf3readyTff7b72.Td2a8ffis_fileTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3pubTff7b72.Td2a8ffpollTb4b4b4(Tb4b4b4) Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3stdoutTb4b4b4, Te6edf3stderr Tff7b72= Te6edf3pubTff7b72.Td2a8ffcommunicateTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff5Tb4b4b4)
Tff7b72raise Tf85149AssertionErrorTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffpublisher exited Tffd700{Te6edf3pubTff7b72.Td2a8ffreturncodeTffd700}Ta5d6ff: Tffd700{Te6edf3stderrTffd700}Tffea00\nTffd700{Te6edf3stdoutTffd700}Ta5d6ff"
Tb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.2Tb4b4b4)
Tff7b72assert Te6edf3readyTff7b72.Td2a8ffis_fileTb4b4b4(Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffpublisher did not write ready.jsonTa5d6ff"
Te6edf3cli Tff7b72= Te6edf3subprocessTff7b72.Td2a8ffPopenTb4b4b4(
Tb4b4b4[Te6edf3sysTff7b72.Td2a8ffexecutableTb4b4b4, Ta5d6ff"Ta5d6ff-cTa5d6ff"Tb4b4b4, Te6edf3_CLI_SCRIPTTb4b4b4, Tffa657strTb4b4b4(Te6edf3cli_dirTb4b4b4)Tb4b4b4, Tffa657strTb4b4b4(Te6edf3share_dirTb4b4b4)Tb4b4b4]Tb4b4b4,
Te6edf3stdoutTff7b72=Te6edf3subprocessTff7b72.Td2a8ffPIPETb4b4b4,
Te6edf3stderrTff7b72=Te6edf3subprocessTff7b72.Td2a8ffPIPETb4b4b4,
Te6edf3textTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3envTff7b72=Te6edf3envTb4b4b4,
Tb4b4b4)
Te6edf3result_path Tff7b72= Te6edf3share_dir Tff7b72/ Ta5d6ff"Ta5d6ffresult.jsonTa5d6ff"
Te6edf3deadline Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72+ T79c0ff40
Tff7b72while Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3deadline Tff7b72and Tff7b72not Te6edf3result_pathTff7b72.Td2a8ffis_fileTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3cliTff7b72.Td2a8ffpollTb4b4b4(Tb4b4b4) Tff7b72is Tff7b72not Tff7b72None Tff7b72and Tff7b72not Te6edf3result_pathTff7b72.Td2a8ffis_fileTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3stdoutTb4b4b4, Te6edf3stderr Tff7b72= Te6edf3cliTff7b72.Td2a8ffcommunicateTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff5Tb4b4b4)
Tff7b72raise Tf85149AssertionErrorTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffclient exited Tffd700{Te6edf3cliTff7b72.Td2a8ffreturncodeTffd700}Ta5d6ff: Tffd700{Te6edf3stderrTffd700}Tffea00\nTffd700{Te6edf3stdoutTffd700}Ta5d6ff"
Tb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.2Tb4b4b4)
Tff7b72assert Te6edf3result_pathTff7b72.Td2a8ffis_fileTb4b4b4(Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffclient did not write result.jsonTa5d6ff"
Te6edf3payload Tff7b72= Te6edf3jsonTff7b72.Td2a8ffloadsTb4b4b4(Te6edf3result_pathTff7b72.Td2a8ffread_textTb4b4b4(Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72assert Te6edf3payloadTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffokTa5d6ff"Tb4b4b4) Tff7b72is Tff7b72TrueTb4b4b4, Te6edf3payload
Tff7b72assert Te6edf3payloadTb4b4b4[Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffCampTa5d6ff"
Tff7b72assert Te6edf3payloadTb4b4b4[Ta5d6ff"Ta5d6ffmap_idTa5d6ff"Tb4b4b4] Tff7b72== Te6edf3payloadTb4b4b4[Ta5d6ff"Ta5d6ffpublished_idTa5d6ff"Tb4b4b4]
Tff7b72assert Te6edf3payloadTb4b4b4[Ta5d6ff"Ta5d6ffsizeTa5d6ff"Tb4b4b4] Tff7b72> T79c0ff0
Tff7b72finallyTb4b4b4:
Tb4b4b4(Te6edf3share_dir Tff7b72/ Ta5d6ff"Ta5d6ffstopTa5d6ff"Tb4b4b4)Tff7b72.Td2a8ffwrite_textTb4b4b4(Ta5d6ff"Ta5d6ff1Ta5d6ff"Tb4b4b4, Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)
Tff7b72for Te6edf3proc Tff7b72in Tb4b4b4(Te6edf3cliTb4b4b4, Te6edf3pubTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3proc Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72continue
Tff7b72tryTb4b4b4:
Te6edf3procTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff8Tb4b4b4)
Tff7b72except Te6edf3subprocessTff7b72.Td2a8ffTimeoutExpiredTb4b4b4:
Te6edf3procTff7b72.Td2a8ffkillTb4b4b4(Tb4b4b4)
Te6edf3procTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff5Tb4b4b4)

Served by rngit 1.5.2 - Generated in 0.02s